package com.fenghuajueli.libbasecoreui.upload.pangrowth

import android.app.Application
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.webkit.WebSettings
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.blankj.utilcode.util.DeviceUtils
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.NetworkUtils
import com.fenghuajueli.lib_net.LoggingInterceptor
import com.fenghuajueli.libbasecoreui.upload.UploadService
import com.fenghuajueli.libbasecoreui.utils.MmkvUtils
import com.umeng.analytics.pro.ba
import com.umeng.commonsdk.UMConfigure
import com.umeng.commonsdk.listener.OnGetOaidListener
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.security.MessageDigest
import java.util.*
import java.util.concurrent.TimeUnit


class PangrowthUtils {

    /**
     * 回调地址
     * 运营给的是这个格式
     * https://www.csjplatform.com/growth_dispatcher/api/attribution_callback_self_built/f7cba651-471b-c46b-0fce-f30de94399bd/android?pg_site_id=5356665&signature=${请用相关方式生成}
     * 这里先把android?pg_site_id=5356665&signature=${请用相关方式生成}去掉，签名密钥秘钥后自动加上
     */
    private var callBackUrl = ""

    /**
     * 在回调地址里拆出来的pg_site_id
     */
    private var pgSiteId = ""

    /**
     * 签名密钥
     * 运营给的
     */
    private var secretKey = ""

    /**
     * 广告账户id
     * 运营给的
     */
    private var adAccountId: String? = ""

    /**
     * 广告计划id
     * 运营给的
     */
    private var campaignId: String? = ""

    /**
     * 广告计划名称
     * 运营给的
     */
    private var campaignName: String? = ""


    private var oaid: String? = ""
    private var uniqueId: String? = ""
    private var androidId: String? = ""
    private var macAddress: String? = ""
    private var ipAddress: String? = ""
    private var userAgent: String? = ""
    private val FIRST_LAUNCH = "FIRST_LAUNCH"

    private lateinit var uploadService: UploadService

    companion object {
        @JvmStatic
        val instance: PangrowthUtils by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            PangrowthUtils()
        }
    }

    init {
        initUploadLocalService()
    }

    /**
     * 获取OAID
     *
     * @param application
     * @param onGetOaidListener
     */
    fun initOaidAction(application: Application, onGetOaidListener: OnGetOaidListener?) {
        try {
            UMConfigure.getOaid(application) {
                oaid = it
                onGetOaidListener?.onGetOaid(it)
            }
        } catch (e: Exception) {
            onGetOaidListener?.onGetOaid("")
            e.printStackTrace()
        }
    }

    /**
     * 初始化参数
     *
     * @param callBackUrl 必填：回调地址
     * 运营给的是这个格式 https://www.csjplatform.com/growth_dispatcher/api/attribution_callback_self_built/f7cba651-471b-c46b-0fce-f30de94399bd/android?pg_site_id=5356665&signature=${请用相关方式生成}
     * 这里需要把pg_site_id=5356665&signature=${请用相关方式生成}去掉
     *
     * @param pgSiteId 必填：在回调地址里拆出来的pg_site_id
     * @param secretKey 必填：运营给的签名密钥
     * @param adAccountId 运营给的广告账户id
     * @param campaignId 运营给的广告计划id
     * @param campaignName 运营给的广告计划名称
     */
    fun initConfig(callBackUrl: String, pgSiteId: String, secretKey: String, adAccountId: String? = "", campaignId: String? = "", campaignName: String? = "") {
        this.callBackUrl = callBackUrl
        this.pgSiteId = pgSiteId
        this.secretKey = secretKey
        this.adAccountId = adAccountId
        this.campaignId = campaignId
        this.campaignName = campaignName
    }

    /**
     * 获取OAID
     * 需要放在子线程
     * @param application
     */
    private fun initDeviceId(application: Application) {
        if (oaid.isNullOrEmpty()) {
            //oaid = ba.a(application)
        }
        if (uniqueId.isNullOrEmpty()) {
            uniqueId = DeviceUtils.getUniqueDeviceId()
        }
        if (androidId.isNullOrEmpty()) {
            androidId = DeviceUtils.getAndroidID()
        }
        if (macAddress.isNullOrEmpty()) {
            macAddress = DeviceUtils.getMacAddress()
        }
        if (ipAddress.isNullOrEmpty()) {
            ipAddress = NetworkUtils.getIPAddress(true)
        }
        if (userAgent.isNullOrEmpty()) {
            userAgent = getUserAgent(application)
        }
    }

    /**
     * 上传设备安装时间
     */
    fun openAction(lifecycleOwner: LifecycleOwner, application: Application) {
        if (callBackUrl.isEmpty()) {
            throw NullPointerException("回调地址参数为空,请调用initConfig()初始化参数")
        }
        if (callBackUrl.contains("pg_site_id") || callBackUrl.contains("signature")) {
            throw IllegalArgumentException("回调地址参数错误,pg_site_id=5356665&signature\\\${请用相关方式生成}去掉")
        }
        if (secretKey.isEmpty()) {
            throw NullPointerException("签名密钥参数为空,请调用initConfig()初始化参数")
        }
        lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
            runCatching {
                if (checkIsFirstInstall(application)) {
                    uploadActiveData(application)
                    MmkvUtils.get(FIRST_LAUNCH, false)
                }
            }
        }
    }

    private fun checkIsFirstInstall(application: Application): Boolean {
        val packageManager = application.packageManager
        val packageInfo = packageManager.getPackageInfo(application.packageName, 0)
        return packageInfo.firstInstallTime == packageInfo.lastUpdateTime && MmkvUtils.get(FIRST_LAUNCH, true)
    }

    private suspend fun uploadActiveData(application: Application) {
        initDeviceId(application)

        val installTime = application.getInstallTime()
        if (installTime == 0L) {
            return
        }

        val contentsMap = hashMapOf<String, String>()
        contentsMap.apply {
            //激活时间,必填
            contentsMap["time_ts"] = "$installTime"
            //oaid,必填
            oaid?.let { contentsMap["oaid"] = it }


            //包名
            contentsMap["package"] = application.packageName

            //自归因平台设备唯一标识
            uniqueId?.let { contentsMap["unique_id"] = it }

            //android_id
            androidId?.let { contentsMap["android_id"] = it }

            //mac地址
            macAddress?.let { contentsMap["mac"] = it }

            //ip地址
            ipAddress?.let { contentsMap["ip"] = it }

            //User-Agent
            userAgent?.let { contentsMap["ua"] = it }


            //商标
            contentsMap["device_brand"] = Build.BRAND
            //机型
            contentsMap["model"] = Build.MODEL
            //系统版本
            contentsMap["os_version"] = Build.PRODUCT
            //系统语言
            contentsMap["language"] = Locale.getDefault().language


            //广告投放平台
            contentsMap["ad_platform"] = "juliangyinqing"
            //广告账户id
            contentsMap["ad_account_id"] = adAccountId ?: ""
            //广告计划ID
            contentsMap["campaign_id"] = campaignId ?: ""
            //广告计划名称
            contentsMap["campaign_name"] = campaignName ?: ""
        }

        val signature = generateSignature(contentsMap)
        val toJson = GsonUtils.toJson(contentsMap)
        val result = uploadService.uploadDataToCsjService(pgSiteId, signature, toJson.toRequestBody())
        LogUtils.d("上传结果: $result")
    }

    private fun getUserAgent(context: Context?): String? {
        var userAgent: String? = null
        try {
            userAgent = WebSettings.getDefaultUserAgent(context)
        } catch (ignored: Throwable) {
        }
        if (userAgent == null) {
            userAgent = System.getProperty("http.agent")
        }
        val sb = StringBuilder()
        if (userAgent != null) {
            var i = 0
            val length = userAgent.length
            while (i < length) {
                val c = userAgent[i]
                if (c <= '\u001f' || c >= '\u007f') {
                    sb.append(String.format("\\u%04x", c.code))
                } else {
                    sb.append(c)
                }
                i++
            }
            userAgent = sb.toString()
        }
        return userAgent
    }

    @Throws(PackageManager.NameNotFoundException::class)
    private fun Application.getInstallTime(): Long {
        var installTime: Long = 0
        try {
            installTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
        return installTime
    }

    /**
     * md5加密
     */
    private fun generateSignature(dataMap: Map<String, String>): String {
        val dataBeforeMD5 = StringBuilder()

        TreeMap(dataMap).forEach { data ->
            if (!data.value.isNullOrEmpty()) {
                dataBeforeMD5
                    .append(data.key)
                    .append("=")
                    .append(data.value)
                    .append("&")
            }
        }

        dataBeforeMD5.append("secretKey=").append(secretKey)
        val digest = MessageDigest.getInstance("MD5").digest(dataBeforeMD5.toString().toByteArray())
        return String(encodeHex(digest))
    }

    private fun encodeHex(data: ByteArray): CharArray {
        val digitsLower = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f')

        val l = data.size
        val out = CharArray(l shl 1)

        var i = 0
        var j = 0
        while (i < l) {
            out[j++] = digitsLower[0xF0 and data[i].toInt() ushr 4]
            out[j++] = digitsLower[0x0F and data[i].toInt()]
            i++
        }
        return out
    }


    private fun initUploadLocalService() {
        val logInterceptor = HttpLoggingInterceptor(LoggingInterceptor())
        logInterceptor.level = HttpLoggingInterceptor.Level.BODY
        val builder = OkHttpClient.Builder()
        val okHttpClient = builder
            .readTimeout(15000, TimeUnit.MILLISECONDS)
            .connectTimeout(15000, TimeUnit.MILLISECONDS)
            .addInterceptor(logInterceptor)
            .build()

        uploadService = Retrofit.Builder()
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(callBackUrl)
            .build().create(UploadService::class.java)
    }
}